當我們在開發 Flutter 時,有些時候我們會需要不斷的改變狀態,並把改變後的狀態渲染至畫面上。當隨著需求越來越複雜,改變狀態的邏輯也會開始變得複雜。假設今天有一個選擇相片的功能:畫面中有一個相片列表,使用者可以透過點擊相片選取,並且選取有些限制。
https://dartpad.dev/?id=dd689d7e21bfadcb7c2df8805552a3b6
一開始,我們會嘗試使用 StatefulWidget 來實現,但是從上面的程式碼可以得知,使用 StatefulWidget 會造成一個問題:那就是邏輯與畫面樣式混再一起,造成 Widget 違反了單一職責。
為了解決這個問題,我們來嘗試使用傳統物件導向的方式來解決。運用抽取類別的技巧,將複雜的選取邏輯抽到 SelectedPhotos 中,讓 SelectedPhotos 自己決定照片是否能被選取。
https://dartpad.dev/?id=886bcbddaf299475a141d22e7d099a4e
當我們把 SelectPhotos 的狀態與邏輯抽取至獨立類別後,原本的 Widget 就變得簡單許多。將 SelectPhotos 獨立成一個類別,我們也更好對其邏輯進行單元測試。關於測試的議題,我們會在未來的文章進行討論,這邊就不延伸討論。
在開發客端應用程式時,我們時常會需要在程式中維護狀態。使用者通過 UI 介面操作狀態,程式根據使用者的操作來改變狀態,最後把最終狀態渲染在畫面上。我們可以使用 StatefulWidget 來進行狀態管理,就像上面的例子一樣,但是當邏輯變得複雜,就會造成 Widget 變大而難以修改。
除了使用傳統的物件導向技巧處理,我們還可以選擇引入狀態管理套件,幫助我們簡化設計,在這邊我們使用 Riverpod 來修改上面的例子。
https://dartpad.dev/?id=427c1a2f44a98474a89f35e10aa9f313
相比於抽取類別的作法,使用狀態管理的作法會與前者有兩處不同
雖然在程式碼的長度並不會差很多,但實際上,使用狀態管理套件能讓我們更專注在操作狀態即可,是否重新渲染畫面則交由狀態管理決定,減輕 Widget 的負擔。
當程式邏輯開始變得複雜時,適時的引入狀態管理套件,能有效的簡化設計。雖然在上面的例子中,我自己是使用 riverpod 解決問題,但是 Flutter 還有許多非常優秀的的狀態管理套件,例如:Bloc、Redux …等,Flutter 官方也有給出一些選項:List of state management approaches,大家在開發時,也可以參考看看。